﻿//   AppStorageService.cs
//   Copyright (c) 2012 Eswar Prakash
// 
//    This library is free software; you can redistribute it and/or modify  
//    it  under the terms of the GNU Lesser General Public License version  
//    2.1 as published by the Free Software Foundation.                     
//                                                                          
//    This library is distributed in the hope that it will be useful, but   
//    WITHOUT ANY WARRANTY; without even the implied warranty of            
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     
//    Lesser General Public License for more details.                       
//                                                                          
//    You should have received a copy of the GNU Lesser General Public      
//    License along with this library; if not, write to the Free Software   
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  
//    USA

namespace CKSAS.AppStorage.SharedService
{
    using System;
    using Microsoft.SharePoint.Administration;
    using System.Runtime.InteropServices;
    using Core.Diagnostics;

    /// <summary>
    /// Represents an instance of the AppStorage service in a SharePoint farm
    /// </summary>
    [Guid("15535ad1-2e9e-4612-a781-01e6ff1838a3")]
    internal sealed class AppStorageService : SPIisWebService, IServiceAdministration
    {
        /// <summary>
        /// Private constant to hold the name of the service as displayed in Central Administration
        /// </summary>
        private const string SERVICE_TYPE_NAME = "Application Storage Service";

        /// <summary>
        /// Private constant to hold the description of the service as displayed in Central Administration
        /// </summary>
        private const string SERVICE_TYPE_DESCRIPTION = "Provides storage services for SharePoint applications";

        /// <summary>
        /// Initializes a new instance of the <see cref="AppStorageService"/> class.
        /// </summary>
        public AppStorageService()
            : base()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="AppStorageService"/> class.
        /// </summary>
        /// <param name="farm">The farm where the storage service is located</param>
        public AppStorageService(SPFarm farm)
            : base(farm)
        {
        }

        /// <summary>
        /// Creates a new Application Storage Service Application
        /// </summary>
        /// <param name="name">The name of the service application</param>
        /// <param name="serviceApplicationType">The type of the service application instance</param>
        /// <param name="provisioningContext">The provisioning context to use to provision the service application</param>
        /// <returns>
        /// Returns <see cref="T:Microsoft.SharePoint.Administration.SPServiceApplication"/>.
        /// </returns>
        SPServiceApplication IServiceAdministration.CreateApplication(string name, Type serviceApplicationType,
                                                                      SPServiceProvisioningContext provisioningContext)
        {
            if (typeof (AppStorageServiceApplication) != serviceApplicationType)
            {
                return null;
            }

            // check if there is already a application by name
            var applicationByName = GetApplicationByName(name);
            if (applicationByName == null)
            {
                var dbParameters = SPDatabaseParameters.CreateParameters("AppStorageService",
                                                                         SPDatabaseParameterOptions.GenerateUniqueName);
                applicationByName = this.CreateApplication(name, provisioningContext.IisWebServiceApplicationPool,
                                                           dbParameters);
            }

            return applicationByName;
        }

        /// <summary>
        /// Creates a new application storage service application proxy instance
        /// </summary>
        /// <param name="name">The name of the service application proxy</param>
        /// <param name="serviceApplication">The service application instance to which the proxy is being created</param>
        /// <param name="provisioningContext">The provisioning context to use</param>
        /// <returns>
        /// Returns <see cref="T:Microsoft.SharePoint.Administration.SPServiceApplicationProxy"/>.
        /// </returns>
        SPServiceApplicationProxy IServiceAdministration.CreateProxy(string name,
                                                                     SPServiceApplication serviceApplication,
                                                                     SPServiceProvisioningContext provisioningContext)
        {
            if (serviceApplication == null)
            {
                throw new ArgumentNullException("serviceApplication");
            }

            if (typeof (AppStorageServiceApplication) != serviceApplication.GetType())
            {
                throw new NotSupportedException();
            }

            // create the new proxy
            var proxy = AppStorageServiceProxy.Local.GetApplicationProxy(name);
            if (proxy != null)
            {
                return proxy;
            }

            return new AppStorageServiceApplicationProxy(name, AppStorageServiceProxy.Local,
                                                        (AppStorageServiceApplication) serviceApplication);
        }

        /// <summary>
        /// Creates the service application proxy to an AppStorageServiceApplication instance
        /// </summary>
        /// <param name="name">The name of the proxy.</param>
        /// <param name="serviceApplication">The service application to create a proxy for.</param>
        /// <returns></returns>
        internal AppStorageServiceApplicationProxy CreateApplicationProxy(string name,
                                                                         AppStorageServiceApplication serviceApplication)
        {
            if (serviceApplication == null)
            {
                throw new ArgumentNullException("serviceApplication");
            }

            // create the new proxy
            var proxy = AppStorageServiceProxy.Local.GetApplicationProxy(name);
            if (proxy != null)
            {
                return proxy;
            }

            return new AppStorageServiceApplicationProxy(name, AppStorageServiceProxy.Local, serviceApplication);
        }

        /// <summary>
        /// Gets the application type description of the service application.
        /// </summary>
        /// <param name="serviceApplicationType">The type of the service application for which the description must be returned</param>
        /// <returns>
        /// Returns <see cref="T:Microsoft.SharePoint.Administration.SPPersistedTypeDescription"/>.
        /// </returns>
        SPPersistedTypeDescription IServiceAdministration.GetApplicationTypeDescription(Type serviceApplicationType)
        {
            if (serviceApplicationType != typeof (AppStorageServiceApplication))
            {
                throw new NotSupportedException();
            }

            return new SPPersistedTypeDescription(SERVICE_TYPE_NAME, SERVICE_TYPE_DESCRIPTION);
        }

        /// <summary>
        /// Gets an array of types representing all the service applications that is supported
        /// by this service
        /// </summary>
        /// <returns>
        /// Returns an array of <see cref="T:System.Type"/>.
        /// </returns>
        Type[] IServiceAdministration.GetApplicationTypes()
        {
            return new Type[] {typeof (AppStorageServiceApplication)};
        }

        /// <summary>
        /// Gets the link to the page that displays additional parameters for the service application
        /// and provisions a service application
        /// </summary>
        /// <param name="serviceApplicationType">The type of the service application that is being created</param>
        /// <returns>
        /// Returns <see cref="T:Microsoft.SharePoint.Administration.SPAdministrationLink"/>.
        /// </returns>
        SPAdministrationLink IServiceAdministration.GetCreateApplicationLink(Type serviceApplicationType)
        {
            return new SPAdministrationLink("/_admin/CKSAS/AppStorage/CreateApplication.aspx");
        }

        /// <summary>
        /// Gets the application creation options supported by the service application
        /// </summary>
        /// <param name="serviceApplicationType">The type of the service application that is being created<</param>
        /// <returns>
        /// Returns <see cref="T:Microsoft.SharePoint.Administration.SPCreateApplicationOptions"/>.
        /// </returns>
        SPCreateApplicationOptions IServiceAdministration.GetCreateApplicationOptions(Type serviceApplicationType)
        {
            return SPCreateApplicationOptions.None;
        }

        /// <summary>
        /// Creates the service application given it's name and an application pool
        /// configuration
        /// </summary>
        /// <param name="name">The name of the service application to create.</param>
        /// <param name="applicationPool">The application pool to use for the service application</param>
        /// <param name="dbParameters">The database parameters to use to provision the service database.</param>
        /// <returns></returns>
        internal AppStorageServiceApplication CreateApplication(string name,
                                                               SPIisWebServiceApplicationPool applicationPool,
                                                               SPDatabaseParameters dbParameters)
        {
            LoggingUtilities.WriteTraceEntry(DiagnosticsAreas.CKSAS, DiagnosticCategories.AppStorageService, TraceSeverity.Medium,
                                             "Creating service application instance: {0}", name);
            var application = AppStorageServiceApplication.Create(name, this, applicationPool, dbParameters);
            application.Update();

            // add default end points
            LoggingUtilities.WriteTraceEntry(DiagnosticsAreas.CKSAS, DiagnosticCategories.AppStorageService, TraceSeverity.Medium,
                                             "Adding http endpoint for service application instance: {0}", name);
            application.AddServiceEndpoint("http", SPIisWebServiceBindingType.Http);
            LoggingUtilities.WriteTraceEntry(DiagnosticsAreas.CKSAS, DiagnosticCategories.AppStorageService, TraceSeverity.Medium,
                                             "Adding https endpoint for service application instance: {0}", name);
            application.AddServiceEndpoint("https", SPIisWebServiceBindingType.Https, "secure");

            return application;
        }

        /// <summary>
        /// Gets the local instance of the Auto numbering service
        /// </summary>
        internal static AppStorageService Local
        {
            get
            {
                if (SPFarm.Local != null)
                {
                    return SPFarm.Local.Services.GetValue<AppStorageService>();
                }

                return null;
            }
        }

        /// <summary>
        /// Gets an instance of the AppStorage service application given it's name
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        internal AppStorageServiceApplication GetApplicationByName(string name)
        {
            return base.Applications.GetValue<AppStorageServiceApplication>(name);
        }
    }
}